/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */

#ifndef __M2_MODEL_INFO_H__
#define __M2_MODEL_INFO_H__

#include "M2File.h"
#include "OgreResource.h"

namespace PQGameCore
{
	#define	REGION_FAC	2
	#define	REGION_PX	(256*REGION_FAC)

	/*Charater equpment slot
	*/
	enum CharSlots {
		CS_HEAD,
		CS_NECK,
		CS_SHOULDER,
		CS_BOOTS,
		CS_BELT,
		CS_SHIRT,
		CS_PANTS,
		CS_CHEST,
		CS_BRACERS,
		CS_GLOVES,
		CS_HAND_RIGHT,
		CS_HAND_LEFT,
		CS_CAPE,
		CS_TABARD,
		CS_QUIVER,
		
		NUM_CHAR_SLOTS
	};

	class CharDetails{
	public:
		Ogre::uint race, gender;
		Ogre::uint useNPC;
		Ogre::uint skinColor;
		Ogre::uint faceType;
		Ogre::uint hairColor;
		Ogre::uint hairStyle;
		Ogre::uint facialHair;
		Ogre::uint facialColor;
		Ogre::uint maxFacialColor;
		Ogre::uint maxHairStyle, maxHairColor, maxSkinColor, maxFaceType, maxFacialHair;
		bool showUnderwear, showEars, showHair, showFacialHair, showFeet;
		int equipment[NUM_CHAR_SLOTS];
		static const int NUM_M2_SUBMESH = 16;
		int submeshes[NUM_M2_SUBMESH];
		CharDetails();
		CharDetails(Ogre::uint race,Ogre::uint gender);
	};

	struct CharTexCoord {
		int xpos;
		int ypos;
		int xsize;
		int ysize;
	};

	enum CharTexRegion {
		TEX_REGION_BASE = 0,
		TEX_REGION_ARM_UPPER,
		TEX_REGION_ARM_LOWER,
		TEX_REGION_HAND,
		TEX_REGION_FACE_UPPER,
		TEX_REGION_FACE_LOWER,
		TEX_REGION_TORSO_UPPER,
		TEX_REGION_TORSO_LOWER,
		TEX_REGION_PELVIS_UPPER,
		TEX_REGION_PELVIS_LOWER,
		TEX_REGION_FOOT,
		NUM_REGIONS,

		TEX_REGION_LEG_UPPER = TEX_REGION_PELVIS_UPPER,
		TEX_REGION_LEG_LOWER =TEX_REGION_PELVIS_LOWER
	};

	const CharTexCoord charTexRegion[NUM_REGIONS] =
	{
		{0, 0, 256*REGION_FAC, 256*REGION_FAC},	// base
		{0, 0, 128*REGION_FAC, 64*REGION_FAC},	// arm upper
		{0, 64*REGION_FAC, 128*REGION_FAC, 64*REGION_FAC},	// arm lower
		{0, 128*REGION_FAC, 128*REGION_FAC, 32*REGION_FAC},	// hand
		{0, 160*REGION_FAC, 128*REGION_FAC, 32*REGION_FAC},	// face upper
		{0, 192*REGION_FAC, 128*REGION_FAC, 64*REGION_FAC},	// face lower
		{128*REGION_FAC, 0, 128*REGION_FAC, 64*REGION_FAC},	// torso upper
		{128*REGION_FAC, 64*REGION_FAC, 128*REGION_FAC, 32*REGION_FAC},	// torso lower
		{128*REGION_FAC, 96*REGION_FAC, 128*REGION_FAC, 64*REGION_FAC}, // pelvis upper
		{128*REGION_FAC, 160*REGION_FAC, 128*REGION_FAC, 64*REGION_FAC},// pelvis lower
		{128*REGION_FAC, 224*REGION_FAC, 128*REGION_FAC, 32*REGION_FAC}	// foot
	};

	struct CharTexLayer
	{
		std::string fileName;//image file name
		int region;
	};

	//should build a character achive and terrain archive?
	/*According to m2 filename to determine textures
	*/
	class M2ModelInfo 
	{
	public:
		typedef std::map<std::string,M2ModelInfo*> M2ModelInfoMap;
		typedef std::vector<CharTexLayer> TextureLayerList;
	protected:
		M2ModelInfo(M2File* m2File);
	public:
		
		~M2ModelInfo();

		inline bool isCharacter()
		{
			return _isCharacter;
		}

		inline CharTexLayer* getLayer(int index)
		{
			if(index>=_layers.size()||index<0){
				return 0;
			}
			return &_layers[index];
		}

		inline int getLayerCount()
		{
			return _layers.size();
		}

		inline int getTexCount()
		{
			return _texNames.size();
		}

		inline std::string getTexPath(int index)
		{
			if(index>=_texNames.size()||index<0){
				return "";
			}
			return _texNames[index];
		}

		static M2ModelInfo* get(M2File* m2File)
		{
			assert(m2File);
			std::string fileName=m2File->getFileName();
			M2ModelInfoMap::iterator it= _list.find(fileName);
			if(it!=_list.end()){
				return it->second;
			}
			M2ModelInfo* info=new M2ModelInfo(m2File);
			_list.insert(M2ModelInfoMap::value_type(fileName,info));
			return info;
		}

		inline CharDetails& getCharDetail()
		{
			return _details;
		}

		inline std::string getHairTexturePath()
		{
			return _hairTexturePath;
		}

	private:
		void initTex();
		void initCharBodyTex();
		void initCharHairTex();

		void initCharTex2();
		void initCharDetails();
	protected:
		static M2ModelInfoMap _list;
		std::string _path;//model file path,
		bool _isCharacter;
		Ogre::uint _race;//charater race id if model is a wow character model
		Ogre::uint _gender;//
		std::string _raceName;
		std::string _genderName;

		M2File* _m2File;
		M2TexDef* _m2TexDefs;
		int _m2TexCount;
		std::vector<std::string> _texNames;
		TextureLayerList _layers;//only valid when model is character,body layers construct body
		std::string _hairTexturePath;

		CharDetails _details;
	};

}

#endif
